#include "main.h"

//Ponteiro para o arquivo aberto.
static FILE *arquivo;

int main(int argc, char** argv) {
    char* nomeArquivo;

    if(argc > 1) {

    int tamanhoNome = strlen(argv[1]);
    char _nomeArquivo[tamanhoNome + 4];
        if(strlen(argv[1]) <= 4) {
            for(int j = 0; j < tamanhoNome; j++) {
                _nomeArquivo[j] = argv[1][j];
            }
            _nomeArquivo[tamanhoNome] = '.';
            _nomeArquivo[tamanhoNome + 1] = 'c';
            _nomeArquivo[tamanhoNome + 2] = 'm';
            _nomeArquivo[tamanhoNome + 3] = 'm';
            argv[1] = _nomeArquivo;
        }
        if(strcmp(argv[1] + (strlen(argv[1]) - 4), ".cmm") == 0) {
            arquivo = fopen(argv[1], "r+");
            if(arquivo == NULL) {
                fprintf(stderr, "Arquivo Inexistente!\n");
                return EXIT_FAILURE;
            }
            inicializaBuffer(arquivo);
            preencheBuffer();
        } else {
            nomeArquivo = (char*) malloc((strlen(argv[1]) + 4) * sizeof(char));
            sprintf(nomeArquivo, "%s.cmm", argv[1]);
            arquivo = fopen(nomeArquivo, "r+");
            free(nomeArquivo);
            if(arquivo == NULL) {
                fprintf(stderr, "Arquivo Inexistente!\n");
                return EXIT_FAILURE;
            }
            inicializaBuffer(arquivo);
            preencheBuffer();
        }
    } else {
        arquivo = stdin;
        inicializaBuffer(arquivo);
        preencheBuffer();
    }

    inicializaStringLexema();
    inicializaAnalisadorLexico();
    iniciaParser();
    Program* _asa = program();

    VisitorImpASA *va = new VisitorImpASA();
    if (_asa != NULL) _asa->accept(va);
    delete va;

    VisitorAnalisadorSemantico *vs = new VisitorAnalisadorSemantico();
    if (_asa != NULL) _asa->accept(vs);
    delete vs;

    int numErros = getContadorErrosSintaticos();
    int numErrosSemanticos = getContadorErrosSemanticos();

    if(numErros == 0 && numErrosSemanticos == 0) {
        VisitorGeradorARI *vari = new VisitorGeradorARI();
        if( _asa != NULL) _asa->accept(vari);

        fprintf(stdout, "--------------------------------------------------------------\n");
        fprintf(stdout, "---------------------- ARI - AMARAL V3.0 ---------------------\n");
        fprintf(stdout, "--------------------------------------------------------------\n");
        VisitorImpARI *vimp = new VisitorImpARI();
        if(getFragmentListVariaveis() != NULL) getFragmentListVariaveis()->accept(vimp);
        if(getFragmentList() != NULL) getFragmentList()->accept(vimp);

        if(getFragmentListVariaveis() != NULL) {
            VisitorCanonizador* vc = new VisitorCanonizador();
            getFragmentListVariaveis()->accept(vc);
            delete vc;
        }

        if(getFragmentList() != NULL) {
            while(getFlagCanonizouExp() > 0 || getFlagCanonizouStm() > 0) {
                setFlagCanonizouExp(0);
                setFlagCanonizouStm(0);
                VisitorCanonizador* vc = new VisitorCanonizador();
                getFragmentList()->accept(vc);
                delete vc;
            }
        }

        fprintf(stdout, "--------------------------------------------------------------\n");
        fprintf(stdout, "---------------- ARI CANONIZADA - AMARAL V3.0 ----------------\n");
        fprintf(stdout, "--------------------------------------------------------------\n");
        vimp = new VisitorImpARI();

        FragmentList* final = NULL;
        //Concatena os FragmentLists...
        FragmentList* aux = getFragmentListVariaveis();
        if(aux == NULL) {
            final = getFragmentList();
        } else {
            while(aux->proximo != NULL) {
                aux = aux->proximo;
            }
            //Concatena lista de variaveis com a lista de funcoes...
            aux->proximo = getFragmentList();
            final = aux;
        }

        //if(getFragmentListVariaveis() != NULL) getFragmentListVariaveis()->accept(vimp);
        //if(getFragmentList() != NULL) getFragmentList()->accept(vimp);

        final->accept(vimp);


        /**********************************************
        GERACAO DE CODIGO
        **********************************************/
        //VisitorGeradorMIPS* vMips = new VisitorGeradorMIPS();
        //final->accept(vMips);
        //MIPSArquivo("mips.asm");
        arquivoASM("resultado.asm");
        imprimeCodigo(final);

        fprintf(stdout, "\n\n");

        delete vimp;
        delete vari;
        //delete vMips;
    }

    freeLexema();
    fclose(arquivo);
    imprimeTabelaSimbolos();
    limpaTabela();
    delete _asa;

    if(numErros == 0) fprintf(stdout, "Nao foram encontrados erros sintaticos.\n");
    else fprintf(stdout, "Foram encontrados %d erro(s) durante a analise sintatica.\n", numErros);

    if(numErrosSemanticos == 0) fprintf(stdout, "Nao foram encontrados erros semanticos.\n");
    else fprintf(stdout, "Foram encontrados %d erro(s) durante a analise semantica.\n", numErrosSemanticos);

    return EXIT_SUCCESS;
}
